const config = require('./config')
const _util = require('./util')
const _ws = require('ws').Server
const fs = require('fs')
const http = config.port == 443 ? require('https') : require('http')

//请求处理函数
const reqHandle = (req, res) => {
	res.writeHead(403);
	res.write('<h1>Not Request</h1>');
	res.end();
}
const server = config.port == 443 ? http.createServer({key: fs.readFileSync(config.sslKey),cert: fs.readFileSync(config.sslCert)}, reqHandle).listen(config.port) : http.createServer(reqHandle).listen(config.port)
const ws = new _ws({server: server})
const util = new _util({
	config: config
})

//API库
let apis = {}
//WebSocket连接池
let wsPool = {}
//WebSocket临时池
let wsPoolBuffer = {}

//WebSocket广播
const broadcast = (condition = [], _data = {}, ignore = []) => {
	return new Promise( async (resolve, reject) => {
		try {
			let {status, event, data} = _data
			if(!status || !event || !data) {
				console.error('广播数据不合法', _data)
				reject()
			}
			condition.forEach((c) => {
				if(wsPool[c]) {
					for(let clientId in wsPool[c]) {
						try {
							if(ignore && ignore.length > 0 && ignore.indexOf(clientId) != -1) {
								continue
							}
							console.log('广播消息', _data)
							wsPool[c][clientId].send(JSON.stringify({
								status: status,
								data: {
									event: event,
									data: data
								}
							}))
						}
						catch(err) {
							console.error(err)
						}
					}
				}
			})
			resolve()
		}
		catch(err) {
			console.error(err)
			reject()
		}
	})
}

//WebSocket断开事件
const wsClose = async (client) => {
	let {clientId, clientData} = client
	if(wsPoolBuffer[clientId]) {
		console.log(clientId, '断开连接')
		delete wsPoolBuffer[clientId]
	}
	if(clientData && wsPool[clientData.group][clientId]) {
		console.log(clientData.group + '的' + clientId, '断开连接')
		await broadcast([clientData.group], {
			status: 'success',
			event: 'close',
			data: clientData
		}, [clientId])
		delete wsPool[clientData.group][clientId]
	}
}

//WebSocket消息事件
const wsMsg = async (client, msg) => {
	//判断是否连接超时
	if(Date.now() - client.clientTime > config.connExpire) {
		client.send('{"status":"timeout","msg":"连接超时，请重新连接"}')
	}
	//心跳响应
	if(msg == '@heart') {
		client.send('@heart')
		return
	}
	//获取出json数据
	msg = await util.isJson(msg)
	if(!msg || !msg.api || !msg.data || Object.prototype.toString.call(msg.api) != '[object String]') {
		client.send('{"status":"failed","msg":"数据不合法"}')
		wsClose(client)
		client.close()
		return
	}
	console.log(msg)
	if(msg.api == 'user/user/register' && msg.data.group) {
		if(wsPoolBuffer[client.clientId]) {
			if(!wsPool[msg.data.group]) {
				wsPool[msg.data.group] = {}
			}
			wsPoolBuffer[client.clientId].clientData = msg.data
			wsPool[msg.data.group][client.clientId] = wsPoolBuffer[client.clientId]
			delete wsPoolBuffer[client.clientId]
			await broadcast([msg.data.group], {
				status: 'success',
				event: 'otherRegistered',
				data: msg.data
			}, [client.clientId])
			client.send(`{"status":"success","data":{"event":"registered","data":"注册成功"}}`)
			return
		}
		else {
			client.send(`{"status":"failed","msg":"链接已失效"}`)
			wsClose(client)
			client.close()
			return
		}
	}
	if(!client.clientData || !client.clientData.group) {
		client.send('{"status":"failed","msg":"数据不合法"}')
		wsClose(client)
		client.close()
		return
	}
	let temp = msg.api.match(RegExp("(.+/)(.+/)(.+)"))
	if(!temp || !temp[3] || Object.prototype.toString.call(temp[2]) != '[object String]') {
		client.send('{"status":"failed","msg":"数据不合法"}')
		wsClose(client)
		client.close()
		return
	}
	let api = temp[1] + temp[2]
	let fun = temp[3]
	let data = {
		client: client,
		params: msg.data
	}
	console.log(client.clientId, '调用API', api, fun)
	try {
		let result = await apis[api][fun](msg.data, client)
		console.log('返回结果：', result)
		client.send(JSON.stringify({
			status: 'success',
			data: {
				event: result.event,
				data: result.data
			}
		}))
	}
	catch(err) {
		console.error('发生错误', err)
		client.send(JSON.stringify({
			status: 'failed',
			msg: err
		}))
	}
}

//WebSocket连接事件
const wsConn = (client) => {
	let clientId = util.uuid()
	console.log(clientId, '连接成功')
	if(!wsPoolBuffer[clientId]) {
		client.on('close', function() {
			wsClose(this)
		})
		client.on('message', function(msg) {
			wsMsg(this, msg)
		})
		client.clientId = clientId
		client.clientTime = Date.now()
		wsPoolBuffer[clientId] = client
		client.send(`{"status":"success","data":{"event":"connected","clientId":"${clientId}"}}`)
	}
}

ws.on('connection', wsConn)

config.apis.forEach((api) => {
	try {
		let _api = require(`./api/${api}`)
		apis[`${api}/`] = new _api({
			config: config,
			util: util,
			broadcast: broadcast
		})
		console.log(api, '加载成功')
	}
	catch(err) {
		console.error(api, '加载失败，原因：', err)
	}
})

console.log('SrcCode服务已运行')